package ro.tm.uvt.lp.raccoon.catchGame.entities.agents;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;

import java.util.ArrayList;
import java.util.List;

import ro.tm.uvt.lp.raccoon.catchGame.entities.Agent;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.DogSniffRaccoonDown;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.DogSniffRaccoonLeft;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.DogSniffRaccoonRight;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.DogSniffRaccoonUp;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffCookieDown;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffCookieLeft;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffCookieRight;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffCookieUp;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffDogDown;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffDogLeft;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffDogRight;
import ro.tm.uvt.lp.raccoon.catchGame.entities.agents.actions.RaccoonSniffDogUp;
import ro.tm.uvt.lp.raccoon.catchGame.entities.perceptions.DogOdor;
import ro.tm.uvt.lp.raccoon.catchGame.entities.perceptions.RaccoonOdor;
import ro.tm.uvt.lp.raccoon.catchGame.entities.physicalObjects.NatureStaticEntity;
import ro.tm.uvt.lp.raccoon.catchGame.environment.Environment;
import ro.tm.uvt.lp.raccoon.catchGame.environment.RaccoonDied;
import ro.tm.uvt.lp.raccoon.catchGame.utils.RandomIntGenerator;

/**
 * Created by user on 1/14/2015.
 */
public class Dog extends Agent {


    private boolean changeMove=true;
    private Vector2 velocity = new Vector2();
    private float oldX, oldY;

    private RaccoonDied listener=Environment.INSTANCE;

    private List<DogOdor> odor=new ArrayList<DogOdor>();
    private int memoryDirection=-1;

    public Dog(Sprite sprite,  int x, int y){
        super(sprite);

        this.setPosition(x,y);

        DogOdor do0=new DogOdor(new Sprite(new Texture("entities/dpaw40.png")));
        do0.setPosition(getX(),getY());
        this.addOdor(do0);

        DogOdor do1=new DogOdor(new Sprite(new Texture("entities/dpaw40.png")));
        do1.setPosition(getX(),getY()+Environment.INSTANCE.getTileHeight());
        this.addOdor(do1);

        DogOdor do2=new DogOdor(new Sprite(new Texture("entities/dpaw40.png")));
        do2.setPosition(getX()+Environment.INSTANCE.getTileWidth(),getY());
        this.addOdor(do2);

        DogOdor do3=new DogOdor(new Sprite(new Texture("entities/dpaw40.png")));
        do3.setPosition(getX(),getY()-Environment.INSTANCE.getTileHeight());
        this.addOdor(do3);

        DogOdor do4=new DogOdor(new Sprite(new Texture("entities/dpaw40.png")));
        do4.setPosition(getX()-Environment.INSTANCE.getTileWidth(),getY());
        this.addOdor(do4);

    }

    private void addOdor(DogOdor dOdor){
        this.odor.add(dOdor);
    }

    public List<DogOdor> getOdor(){
        return this.odor;
    }


    @Override
    public void draw(Batch spriteBatch){
        update(Gdx.graphics.getDeltaTime());
        super.draw(spriteBatch);
    }

    public void update(float delta){



        if(changeMove){

            oldX=getX();
            oldY=getY();

            for(DogOdor dogOdor:odor){
                dogOdor.setOldX((int) dogOdor.getX());
                dogOdor.setOldY((int) dogOdor.getY());
            }

            memoryDirection=chooseDirection();

            switch (memoryDirection){
                case 1:
                    velocity.x=0;
                    velocity.y=40;

                    changeMove=false;
                    break;
                case 2:
                    velocity.x=40;
                    velocity.y=0;

                    changeMove=false;
                    break;

                case 3:
                    velocity.x=0;
                    velocity.y=-40;

                    changeMove=false;
                    break;

                case 4:
                    velocity.x=-40;
                    velocity.y=0;

                    changeMove=false;
                    break;
            }
        }

        boolean collisionX = false;
        boolean collisionY = false;

        // move on x
        setX(getX() + velocity.x * delta);
        for(DogOdor dogOdor:odor){
            dogOdor.setX(dogOdor.getX() + velocity.x * delta);
        }
        setY(getY() + velocity.y * delta);
        for(DogOdor dogOdor:odor){
            dogOdor.setY(dogOdor.getY() + velocity.y * delta);
        }

        if(getX()==oldX && (getY()>=oldY+Environment.INSTANCE.getTileHeight() || getY()<=oldY-Environment.INSTANCE.getTileHeight()))
            changeMove=true;

        if(getY()==oldY && (getX()>=oldX+Environment.INSTANCE.getTileWidth() || getX()<=oldX-Environment.INSTANCE.getTileWidth()))
            changeMove=true;

        //collides with nature
        if(collidesWithNature()){
            velocity.x=0;
            velocity.y=0;
            setX(oldX);
            setY(oldY);

            for(DogOdor dogOdor:odor) {
                dogOdor.setX(dogOdor.getOldX());
                dogOdor.setY(dogOdor.getOldY());
            }

            changeMove=true;
        }

        //collides with limits / stay within limits
        //deal with the odor
        collidesWithLeftLimit();
        collidesWithRightLimit();
        collidesWithUpperLimit();
        collidesWithBottomLimit();

    }

    private void collidesWithLeftLimit(){
        if (getX() < 0) {
            float x=0;
            setX(x);
            velocity.x = 0;
            velocity.y = 0;
            this.odor.get(0).setPosition(getX(), getY());
            this.odor.get(1).setPosition(getX(), getY() + Environment.INSTANCE.getTileHeight());
            this.odor.get(2).setPosition(getX() + Environment.INSTANCE.getTileWidth(), getY());
            this.odor.get(3).setPosition(getX(), getY() - Environment.INSTANCE.getTileHeight());
            this.odor.get(4).setPosition(getX()-Environment.INSTANCE.getTileWidth(), getY());

            changeMove = true;
        }
    }

    private void collidesWithRightLimit(){
        if (getX() > Environment.INSTANCE.getWidth() - Environment.INSTANCE.getTileWidth()) {
            float x= Environment.INSTANCE.getWidth() - Environment.INSTANCE.getTileWidth();
            setX(x);
            velocity.x = 0;
            velocity.y = 0;
            this.odor.get(0).setPosition(getX(), getY());
            this.odor.get(1).setPosition(getX(), getY() + Environment.INSTANCE.getTileHeight());
            this.odor.get(2).setPosition(getX() + Environment.INSTANCE.getTileWidth(), getY());
            this.odor.get(3).setPosition(getX(), getY() - Environment.INSTANCE.getTileHeight());
            this.odor.get(4).setPosition(getX()-Environment.INSTANCE.getTileWidth(), getY());
            changeMove = true;
        }
    }

    private void collidesWithUpperLimit(){
        if (getY() > Environment.INSTANCE.getHeight() - Environment.INSTANCE.getTileHeight()) {
            float y=Environment.INSTANCE.getHeight() - Environment.INSTANCE.getTileHeight();
            setY(y);
            velocity.x = 0;
            velocity.y = 0;
            this.odor.get(0).setPosition(getX(), getY());
            this.odor.get(1).setPosition(getX(), getY() + Environment.INSTANCE.getTileHeight());
            this.odor.get(2).setPosition(getX() + Environment.INSTANCE.getTileWidth(), getY());
            this.odor.get(3).setPosition(getX(), getY() - Environment.INSTANCE.getTileHeight());
            this.odor.get(4).setPosition(getX()-Environment.INSTANCE.getTileWidth(), getY());
            changeMove = true;
        }
    }

    private void collidesWithBottomLimit(){
        if (getY() < 0) {
            float y= 0;
            setY(y);
            velocity.x = 0;
            velocity.y = 0;
            this.odor.get(0).setPosition(getX(), getY());
            this.odor.get(1).setPosition(getX(), getY() + Environment.INSTANCE.getTileHeight());
            this.odor.get(2).setPosition(getX() + Environment.INSTANCE.getTileWidth(), getY());
            this.odor.get(3).setPosition(getX(), getY() - Environment.INSTANCE.getTileHeight());
            this.odor.get(4).setPosition(getX()-Environment.INSTANCE.getTileWidth(), getY());
            changeMove = true;
        }
    }


    private boolean collidesWithNature(){
        for(NatureStaticEntity nse:Environment.INSTANCE.getNature()){
            Rectangle rectangleFood=new Rectangle(nse.getX(),nse.getY(),40,40);
            Rectangle rectangleCurr=new Rectangle(getX(),getY(),40,40);
            if(rectangleCurr.overlaps(rectangleFood)) return true;
        }
        return false;
    }



    public void resetVelocity(){
        this.velocity.x=0;
        this.velocity.y=0;
    }

    private int chooseDirection(){
        if (new DogSniffRaccoonUp().sniff(getX(),getY()) )
            return 1;
        else if (new DogSniffRaccoonRight().sniff(getX(),getY()))
            return 2;
        else if (new DogSniffRaccoonDown().sniff(getX(),getY()))
            return 3;
        else if (new DogSniffRaccoonLeft().sniff(getX(),getY()) )
            return 4;
        else {
            int direction, newX=(int)oldX, newY=(int)oldY;
            int count=0;
            do {
                direction = RandomIntGenerator.randInt(1, 4);
                count++;
                switch (direction) {
                    case 1:
                        newX=(int)oldX;
                        newY =(int) (40+oldY);


                        break;
                    case 2:
                        newX= (int)(oldX+40);
                        newY=(int)oldY;


                        break;

                    case 3:
                        newX=(int)oldX;
                        newY =(int)(oldY -40);


                        break;

                    case 4:
                        newX =(int) (oldX-40);
                        newY = (int)oldY;


                        break;
                }

            } while (new Rectangle(newX,newY,40,40).overlaps(new Rectangle(oldX,oldY,40,40))&& count<4);
            return direction;
        }
    }
}
